package com.kingbook.core.executor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kingbook.common.thread.ThreadLocalManager;
import com.kingbook.core.exception.DatabaseAccessException;
import com.kingbook.core.sql.dialect.DBDialect;
import com.kingbook.core.utils.JDBCHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.List;
import java.util.Map;

/**
 * @Author: Bucky
 * @Date: 2019/1/2
 * @Version 1.0
 */
@Component
public class DatabaseSupport extends JdbcDaoSupport {

    protected static Logger logger = LoggerFactory.getLogger(DatabaseSupport.class);

    private ParsedNamedParameterJdbcTemplate template;

    @Resource
    void setDataSources(DataSource dataSource) {
        setDataSource(dataSource);
        setDBDialect(dataSource);
        template = new ParsedNamedParameterJdbcTemplate(getJdbcTemplate());
    }

    private void setDBDialect(DataSource dataSource) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            DatabaseMetaData md = connection.getMetaData();
            ThreadLocalManager.set(dataSource, DBDialect.getInstance(md.getDatabaseProductName()));
            logger.info("****** 数据库版本信息: {} {}.{} ******", md.getDatabaseProductName(), md.getDatabaseMajorVersion(), md.getDatabaseMinorVersion());
        } catch (Exception e) {
            throw new DatabaseAccessException("****** 获取数据库信息错误: ", e, logger);
        } finally {
            JDBCHelper.cleanup(connection, null, null);
        }
    }

    public DBDialect getDBDialect() {
        return ThreadLocalManager.get(getDataSource(), DBDialect.class, DBDialect.MYSQL);
    }

    private ParsedNamedParameterJdbcTemplate getTemplate() {
        return template;
    }

    /**
     * 返回第一条记录
     */
    public <T> T find(String sql, Map<String, ?> paramMap, Class<T> clazz) {
        Object t;
        if (Map.class.equals(clazz)) {
            t = getTemplate().query(sql, paramMap, new MapResultSetExtractor());
        } else if (JSONObject.class.equals(clazz)) {
            t = getTemplate().query(sql, paramMap, new JSONObjectResultSetExtractor());
        } else {
            t = getTemplate().query(sql, paramMap, new BeanResultSetExtractor(clazz));
        }
        return (T) t;
    }

    /**
     * 返回Map结果集
     */
    public Map<String, Object>[] queryMap(String sql, Map<String, ?> paramMap) {
        return getTemplate().query(sql, paramMap, new MapArrayResultSetExtractor());
    }


    /**
     * 返回Json结果集
     */
    public JSONArray query(String sql, Map<String, ?> paramMap) {
        return getTemplate().query(sql, paramMap, new JSONArrayResultSetExtractor());
    }

    /**
     * 返回对象结果集
     */
    public <T> List<T> query(String sql, Map<String, ?> paramMap, Class<T> clazz) {
        return getTemplate().queryList(sql, paramMap, new BeanListResultSetExtractor(clazz));
    }

    /**
     * 返回结果集行数
     *
     * @param cSql
     * @param cParamMap
     * @return
     */
    public Integer getRows(String cSql, Map<String, ?> cParamMap) {
        return getTemplate().query(cSql, cParamMap, new SQLCountResultSetExtractor());
    }

    /**
     * 更新记录
     *
     * @param sql
     * @param paramMap
     * @return
     */
    public int update(String sql, Map<String, ?> paramMap) {
        return getTemplate().update(sql, paramMap);
    }

    /**
     * 批量执行多条sql
     *
     * @param sql
     * @return
     */
    public int[] batchUpdate(String... sql) {
        return getJdbcTemplate().batchUpdate(sql);
    }


    /**
     * 插入记录并返回主键
     *
     * @param sql
     * @param paramMap
     * @return
     */
    public int insertReturnKey(String sql, Map<String, ?> paramMap) {
        return getTemplate().insertReturnKey(sql, paramMap);
    }

    /**
     * 批量更新多条记录
     *
     * @param sql
     * @param batchValues
     * @return
     */
    public int[] batchUpdate(String sql, List<Map<String, ?>> batchValues) {
        return getTemplate().batchUpdate(sql, batchValues);
    }

    public int[] batchUpdate(String sql, Map<String, ?>[] batchValues) {
        return getTemplate().batchUpdate(sql, batchValues);
    }

    /**
     * 批量插入多条记录并返回主键
     *
     * @param sql
     * @param batchValues
     * @return
     */
    public int[] batchInsertReturnKey(String sql, List<Map<String, ?>> batchValues) {
        return getTemplate().batchUpdate(sql, batchValues);
    }

    public int[] batchInsertReturnKey(String sql, Map<String, ?>[] batchValues) {
        return getTemplate().batchUpdate(sql, batchValues);
    }


	
/*	boolean execute(String sql,Map<String, ?> paramMap, final PreparedStatementSetter pss) throws DataAccessException {
		logger.debug("Executing SQL:" + sql);
		return new NamedParameterJdbcTemplate(getJdbcTemplate()).execute(sql,paramMap,new PreparedStatementCallback<Boolean>() {
			public Boolean doInPreparedStatement(PreparedStatement ps) throws SQLException {
				try {
					if (pss != null) {
						pss.setValues(ps);
					}
					return ps.execute(); 
				}
				finally {
					if (pss instanceof ParameterDisposer) {
						((ParameterDisposer) pss).cleanupParameters();
					}
				}
			}
		}); 
	}

	boolean execute(final String sql) throws DataAccessException {
		logger.debug("Executing SQL:" + sql);
		return getJdbcTemplate().execute(new StatementCallback<Boolean>(){
			public Boolean doInStatement(Statement stmt) throws SQLException {
				return stmt.execute(sql); 
			} 
		});
	}*/


}
